#include "stdafx.h"
#include "ServiceImpNW.h"
#include "ServiceDataCli.h"
#include "Message/MsgSession.h"
#include "Message/MsgBuilderSimple.h"


ServiceImpNW::ServiceImpNW()
:Session(m_theIoSvc),
m_theEmptyWork(m_theIoSvc),
m_theResolver(m_theIoSvc),
m_wpSvcLgc(NULL),
m_pMsgBuilder(NULL),
m_bConnected(false)
{
	setDataStreamPool(&m_theMsgBuffFact);
}

ServiceImpNW::~ServiceImpNW()
{

}

void
ServiceImpNW::init(ServiceData& data)
{
	ServiceDataCli* pSvcData = dynamic_cast<ServiceDataCli*>(&data);
	if (pSvcData)
	{
		m_wpSvcLgc = pSvcData->m_wpSvcLgc;

		if (!pSvcData->m_wpProps->parse("server", m_strSvrIP))
		{
			LOG_ERROR("Failed to get server ip from properties!");
			m_strSvrIP = "127.0.0.1";
		}
		if (!pSvcData->m_wpProps->parse("port", m_strSvrPort))
		{
			LOG_ERROR("Failed to get server port from properties1");
			m_strSvrPort = "9000";
		}
	}
}

void
ServiceImpNW::onStart()
{
	if (m_pMsgBuilder==NULL)
	{
		m_pMsgBuilder = new MsgBuilderWithFactory;
	}

	autoReconnect();

	__super::onStart();
}

void
ServiceImpNW::onStop()
{
	__super::onStop();
}



void 
ServiceImpNW::onSessionStart(const boost::system::error_code& error,  boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
	if (!error)
	{
		LOG_DEBUG("Success to connect to the server!!!");

		read();

		m_bConnected = true;

		IMsg* pMsg = new MsgSessionOpened();

		m_wpSvcLgc->postMsg(pMsg);
	}
	else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator())
	{
		LOG_DEBUG("Failed to connect to the server!!!");

		getSocket().close();
		boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
		getSocket().async_connect(endpoint,boost::bind(&ServiceImpNW::onSessionStart, this, boost::asio::placeholders::error, ++endpoint_iterator));
	}
	else
	{
		LOG_DEBUG("Failed to connect to the server, timeout!!!");
	}
}

void
ServiceImpNW::onSessionEnd()
{
	LOG_DEBUG("Disconnect from server!!!");


	IMsg* pMsg = new MsgSessionClosed();

	m_wpSvcLgc->postMsg(pMsg);
}

void
ServiceImpNW::onTimer()
{
	//LOG_DEBUG("> Timeout, Network thread!!!");

	autoReconnect();

	__super::onTimer();
}

void
ServiceImpNW::onDispatchMsg(IMsg* pMsg)
{
	int nMsgCate = pMsg->getMsgCate();

	switch(nMsgCate)
	{
	case 0:
		{
			break;
		}
	default:
		{
			MsgBuffer* pBuffer = new MsgBuffer;
			MsgOStream	stream(*pBuffer);


			if (m_pMsgBuilder->onEncodeMsg(pMsg, stream))
			{
				write(pBuffer);
			}
			else
			{
				pMsg->dump();
				LOG_ERROR("Failed to encode upper message!!!");
			}
		}
	}
}

void 
ServiceImpNW::onInput(const boost::system::error_code& error, size_t bytes_transferred, MsgBuffer* buffer )
{
	if (!error)
	{
		if (bytes_transferred>0)
		{
			MsgIStream stream(*buffer);
			buffer->commit(bytes_transferred);

			IMsg* pMsg = NULL;
			if (m_pMsgBuilder->onDecodeMsg(pMsg, stream) && pMsg!=NULL )
			{
				m_wpSvcLgc->postMsg(pMsg);
			}
			else
			{
				LOG_ERROR("Failed to decode message from server!");
			}

			read();
		}
		else
		{
			LOG_INFO("0 bytes transfered, disconnect from server!")
		}
	}
	else
	{
		m_bConnected = false;
		LOG_INFO("Disconnect from server! retry connect later!");
		MsgSessionClosed* msg = new MsgSessionClosed;
		m_wpSvcLgc->postMsg(msg);
	}
}

void
ServiceImpNW::onOutput(const boost::system::error_code& error, size_t bytes_transferred, MsgBuffer* buffer )
{
	if (buffer)
	{
		//	recycle
		//m_wpMsgBufferFactory->free(buffer);

		delete buffer;
	}
}


void
ServiceImpNW::autoReconnect()
{
	if (!m_bConnected)
	{
		boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), m_strSvrIP, m_strSvrPort);
		boost::asio::ip::tcp::resolver::iterator iterator = m_theResolver.resolve(query);

		m_theEndPoint = *iterator;
		getSocket().async_connect(m_theEndPoint, boost::bind(&ServiceImpNW::onSessionStart, this, boost::asio::placeholders::error, iterator));

		LOG_INFO("Trying to connect server!");
	}
}

